package logic;

import gui.GuiMain;

import java.util.ArrayList;
import java.util.Stack;

import storage.Storage;
import memory.GenericEvents;
import memory.Memory;

public class History {
	private static ArrayList<GenericEvents> current = null;
	private static Stack<ArrayList<GenericEvents>> back = new Stack<ArrayList<GenericEvents>>();
	private static Stack<ArrayList<GenericEvents>> forward = new Stack<ArrayList<GenericEvents>>();

	//@author A0096677H
	// Creates a snapshot of changes in the memory and moves previous state into the back stack. forward stack is reinitialized
	public static void advance(Memory memory) {
		forward = new Stack<ArrayList<GenericEvents>>();
		back.push(current);
		current = new ArrayList<GenericEvents>();
		duplicateMemory(memory);
	}

	//@author A0096677H
	// Duplicates memory into the current ArrayList
	private static void duplicateMemory(Memory memory) {
		for (int i=0; i<memory.getSize();i++) { // Duplicating of memory into snapshot
			current.add(new GenericEvents(memory.get(i).getType(),
					memory.get(i).getName(),
					memory.get(i).getDescription(),
					memory.get(i).getStart(),
					memory.get(i).getEnd(),
					memory.get(i).getState()));
		}
	}

	//@author A0096677H
	// Retrieves most recent snapshot in the forward stack and swap it with current memory. Current memory gets pushed into back stack
	public static void redo(Memory memory) {
		if (forward.isEmpty() || (forward.peek() == null)) {
			System.out.println("Nothing to redo!");
			return;
		}
		redoMemorySwap(memory);
		Storage.saveToStorage(memory);
		GuiMain.updateQuickView();
		Time.initTimer(memory);
		Display.displayList(memory.getList(), "Display All");
		System.out.println("Redo successful.");
	}
	
	//@author A0096677H
	// Swaps memory used for redo
	private static void redoMemorySwap(Memory memory) {
		assert forward.size() >0;
		back.push(current);
		current = forward.pop();
		memory.setList(current);
	}

	//@author A0096677H
	// Retrieves most recent snapshot in the back stack and swap it with current memory. Current memory gets pushed into forward stack
	public static void undo(Memory memory) {
		if (back.isEmpty() || (back.peek() == null)) {
			System.out.println("Nothing to undo!");
			return;
		}

		ArrayList<GenericEvents> temp = duplicateTemp(memory);
		undoMemorySwap(memory, temp);
		Storage.saveToStorage(memory);
		GuiMain.updateQuickView();
		Time.initTimer(memory);
		Display.displayList(memory.getList(), "Display All");
		System.out.println("Undo successful.");
	}
	
	//@author A0096677H
	// Swaps memory used for undo
	private static void undoMemorySwap(Memory memory,
			ArrayList<GenericEvents> temp) {
		forward.push(temp);
		current = back.pop();
		assert current != null;
		memory.setList(current);
	}

	//@author A0096677H
	// Duplicate current memory into temp ArrayList
	private static ArrayList<GenericEvents> duplicateTemp(Memory memory) {
		ArrayList<GenericEvents> temp = new ArrayList<GenericEvents>(); // Duplicating of memory into forward stack
		for (int i=0; i<memory.getSize();i++) {
			temp.add(new GenericEvents(memory.get(i).getType(),
					memory.get(i).getName(),
					memory.get(i).getDescription(),
					memory.get(i).getStart(),
					memory.get(i).getEnd(),
					memory.get(i).getState()));
		}
		return temp;
	}

}
